package com.autumn.config.services.impl;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.dubbo.config.annotation.Service;
import com.autumn.common.api.application.dto.output.IPageQueryResult;
import com.autumn.config.api.consts.ConfigureConsts.ConnectionTypeConsts;
import com.autumn.config.api.consts.ConfigureConsts.StatusConsts;
import com.autumn.config.api.dto.input.AppPageQueryInput;
import com.autumn.config.api.dto.input.ApplicationInfoDataSourceInput;
import com.autumn.config.api.dto.input.StatusInput;
import com.autumn.config.api.dto.output.ApplicationInfoDataSourceOutput;
import com.autumn.config.api.services.IApplicationDataSourceService;
import com.autumn.config.api.services.ICacheService;
import com.autumn.config.entities.ApplicationDataSource;
import com.autumn.config.entities.ApplicationInfo;
import com.autumn.config.entities.ConnectionConfigure;
import com.autumn.config.entities.view.ApplicationDataSourceView;
import com.autumn.config.repositories.IApplicationInfoRepository;
import com.autumn.config.repositories.IConnectionConfigureRepository;
import com.autumn.config.repositories.view.IApplicationDataSourceViewRepository;
import com.autumn.config.util.ServiceUtils;
import com.autumn.mybatis.criterion.LockModeEnum;
import com.autumn.util.AutoMapUtils;
import com.autumn.util.DataRollbackException;
import com.autumn.util.ExceptionUtils;
import com.autumn.util.data.DbAuditingUtils;
import com.autumn.util.data.DbQueryUtils;
import com.autumn.util.data.PageQueryBuilder;
import com.autumn.util.tuple.TupleTwo;

/**
 * 应用数据源服务实现
 * 
 * @author 老码农
 *         <p>
 *         Description
 *         </p>
 * @date 2018-01-01 16:54:06
 */
@Service(interfaceClass = IApplicationDataSourceService.class)
@Component
public class ApplicationDataSourceServiceImpl extends
		AbstractConfigureService<ApplicationDataSource, ApplicationDataSourceView, ApplicationInfoDataSourceInput, ApplicationInfoDataSourceInput, ApplicationInfoDataSourceOutput>
		implements IApplicationDataSourceService {

	@Autowired
	private IConnectionConfigureRepository connRepository;

	@Autowired
	private IApplicationInfoRepository appRepository;

	@Autowired
	private IApplicationDataSourceViewRepository viewRepository;

	@Autowired
	private ICacheService cacheService;

	private final static String ID_FILED = "id";

	private TupleTwo<ApplicationInfo, ConnectionConfigure> checkDataSource(ApplicationInfoDataSourceInput input) {
		ExceptionUtils.checkNotNull(input, "input");
		if (input.getSortId() == null) {
			input.setSortId(1);
		}
		if (input.getAppId() == null) {
			ExceptionUtils.throwValidationException("应用 id 不能为空。");
		}
		if (input.getConnectionId() == null) {
			ExceptionUtils.throwValidationException("连接 id 不能为空。");
		}
		if (!ServiceUtils.exist(appRepository, ApplicationInfo.class, ID_FILED, input.getTargetAppId())) {
			ExceptionUtils.throwValidationException("指定的目标应用不存在!");
		}
		ApplicationInfo appInfo = DbQueryUtils.queryById(appRepository, ApplicationInfo.class, input.getAppId());
		if (appInfo == null) {
			ExceptionUtils.throwValidationException("指定的应用不存在!");
		}
		ConnectionConfigure connect = DbQueryUtils.queryById(connRepository, ConnectionConfigure.class,
				input.getConnectionId());
		if (connect == null) {
			ExceptionUtils.throwValidationException("指定的连接不存在!");
		}
		return new TupleTwo<>(appInfo, connect);
	}

	private boolean exist(Long appId, Long targetAppId, Integer connectionType) {
		Map<String, Object> propertyMap = new HashMap<>(16);
		propertyMap.put("appId", appId);
		propertyMap.put("targetAppId", targetAppId);
		propertyMap.put("connectionType", connectionType);
		return ServiceUtils.exist(viewRepository, ApplicationDataSourceView.class, propertyMap);
	}

	@Override
	public ApplicationInfoDataSourceOutput add(ApplicationInfoDataSourceInput input) {
		TupleTwo<ApplicationInfo, ConnectionConfigure> tuple = checkDataSource(input);
		if (this.exist(input.getAppId(), input.getTargetAppId(), tuple.getItem2().getConnectionType())) {
			ApplicationInfo app = appRepository.get(input.getTargetAppId());
			ExceptionUtils.throwValidationException(String.format("目标应用 %s 在同一应用的相同连接类型[%s]已重复。", app.getAppName(),
					ConnectionTypeConsts.getName(tuple.getItem2().getConnectionType())));
		}
		ApplicationDataSource entity = AutoMapUtils.map(input, ApplicationDataSource.class);
		if (entity.getSortId() == null) {
			entity.setSortId(1);
		}
		DbAuditingUtils.insertSetProperty(entity);
		entity.setStatus(StatusConsts.STATUS_DRAFT);
		this.repository.insert(entity);
		cacheService.deleteServiceInfo(tuple.getItem1().getAppId());
		return AutoMapUtils.map(this.getQueryById(entity.getId()), ApplicationInfoDataSourceOutput.class);
	}

	@Override
	public ApplicationInfoDataSourceOutput modify(ApplicationInfoDataSourceInput input) {
		if (input.getId() == null) {
			ExceptionUtils.throwValidationException("Id 不能为空");
		}
		TupleTwo<ApplicationInfo, ConnectionConfigure> tuple = checkDataSource(input);
		ApplicationDataSourceView result = DbQueryUtils.queryById(viewRepository, ApplicationDataSourceView.class,
				input.getId(), LockModeEnum.UPDATE);
		if (result == null) {
			ExceptionUtils.throwValidationException("需要修改的数据源不存在!");
		}
		if (!input.getTargetAppId().equals(result.getTargetAppId())
				|| !tuple.getItem2().getConnectionType().equals(result.getConnectionType())) {
			if (this.exist(input.getAppId(), input.getTargetAppId(), tuple.getItem2().getConnectionType())) {
				ApplicationInfo app = appRepository.get(input.getTargetAppId());
				ExceptionUtils.throwValidationException(String.format("目标应用 %s 在同一应用的相同连接类型[%s]已重复。", app.getAppName(),
						ConnectionTypeConsts.getName(tuple.getItem2().getConnectionType())));
			}
		}
		AutoMapUtils.map(input, result);
		DbAuditingUtils.updateSetProperty(result);
		result.setStatus(StatusConsts.STATUS_DRAFT);
		this.repository.update(result);
		return AutoMapUtils.map(this.getQueryById(result.getId()), ApplicationInfoDataSourceOutput.class);
	}

	@Override
	protected ApplicationDataSource deleteById(Long id) {
		ApplicationDataSource result = super.deleteById(id);
		if (result != null) {
			ApplicationInfo appInfo = appRepository.get(result.getAppId());
			if (appInfo != null) {
				cacheService.deleteServiceInfo(appInfo.getAppId());
			}
		}
		return result;
	}

	@Override
	@Transactional(rollbackFor = DataRollbackException.class)
	public ApplicationInfoDataSourceOutput updateStatus(StatusInput input) {
		ApplicationInfoDataSourceOutput result = super.updateStatus(input);
		if (result != null) {
			ApplicationInfo appInfo = appRepository.get(result.getAppId());
			if (appInfo != null) {
				cacheService.deleteServiceInfo(appInfo.getAppId());
			}
		}
		return result;
	}

	@Override
	public IPageQueryResult<ApplicationInfoDataSourceOutput> queryByPage(AppPageQueryInput input) {
		if (input == null || input.getAppId() == null) {
			ExceptionUtils.throwValidationException("应用Id不能为空");
		}
		PageQueryBuilder<ApplicationDataSourceView> builder = new PageQueryBuilder<>(ApplicationDataSourceView.class);
		return builder.apply(q -> {
			q.eq("appId", input.getAppId()).orderBy("sortId").orderBy("id");
		}).page(input, this.getPageMaxSize()).toPageResult(this.queryRepository, ApplicationInfoDataSourceOutput.class);
	}

}
